<?php

declare(strict_types=1);

namespace wym\taglib;

use DirectoryIterator;
use Exception;

class TagLib extends \think\template\TagLib
{
    /**
     * 定义标签前缀
     */
    protected string $tag = '';

    /**
     * 定义标签对应样式
     */
    protected array $class;

    /**
     * 定义标签通用属性
     */
    protected array $attr;

    /**
     * 分析标签属性 正则方式
     *
     * @access public
     *
     * @param string $str   标签属性字符串
     * @param string $name  标签名
     * @param string $alias 别名
     *
     * @return array
     * @throws \Exception
     */
    public function parseAttr(string $str, string $name, string $alias = ''): array
    {
        $regex  = '/\s+(?>(?P<name>[\w-]+)\s*)=(?>\s*)([\"\'])(?P<value>(?:(?!\\2).)*)\\2/is';
        $result = [];

        if (preg_match_all($regex, $str, $matches)) {
            foreach ($matches['name'] as $key => $val) {
                $result[$val] = $matches['value'][$key];
            }

            if (!isset($this->tags[$name])) {
                // 检测是否存在别名定义
                foreach ($this->tags as $val) {
                    if (isset($val['alias'])) {
                        $array = (array)$val['alias'];

                        if (in_array($name, explode(',', $array[0]))) {
                            $tag            = $val;
                            $label          = !empty($array[1]) ? $array[1] : 'type';
                            $result[$label] = str_replace($this->tag, '', $name);
                            break;
                        }
                    }
                }
            } else {
                $result = $this->extracted($name, $alias, $result);
            }

            if (!empty($tag['must'])) {
                $must = explode(',', $tag['must']);

                foreach ($must as $name) {
                    if (!isset($result[$name])) {
                        throw new Exception('tag attr must:' . $name);
                    }
                }
            }
        } else {
            // 允许直接使用表达式的标签
            if (!empty($this->tags[$name]['expression'])) {
                static $taglibs;

                if (!isset($taglibs[$name])) {
                    $taglibs[$name][0] = strlen($this->tpl->getConfig('taglib_begin_origin') . $name);
                    $taglibs[$name][1] = strlen($this->tpl->getConfig('taglib_end_origin'));
                }
                $result['expression'] = substr($str, $taglibs[$name][0], -$taglibs[$name][1]);
                // 清除自闭合标签尾部/
                $result['expression'] = rtrim($result['expression'], '/');
                $result['expression'] = trim($result['expression']);
            } else {
                if (!isset($this->tags[$name])) {
                    // 检测是否存在别名定义
                    foreach ($this->tags as $val) {
                        if (isset($val['alias'])) {
                            $array = (array)$val['alias'];

                            if (in_array($name, explode(',', $array[0]))) {
                                $label          = !empty($array[1]) ? $array[1] : 'type';
                                $result[$label] = str_replace($this->tag, '', $name);
                                break;
                            }
                        }
                    }
                } else {
                    $result = $this->extracted($name, $alias, $result);
                }

                if (empty($this->tags[$name]) || !empty($this->tags[$name]['attr'])) {
                    throw new Exception('tag error:' . $name);
                }
            }
        }

        return $result;
    }

    /**
     * 生成CLASS和HTML标签
     *
     * @access protected
     *
     * @param array $tag 标签
     *
     * @return array
     */
    protected function getClass(array $tag): array
    {
        [$label, $class] = $this->class[$tag['label']] ?? ['div', ''];

        $class .= empty($tag['class']) ? '' : ' ' . trim($tag['class']);
        $class = empty($class) ? '' : ' class="' . trim($class) . '"';

        return [$label, $class];
    }

    /**
     * 生成HTML属性
     *
     * @access protected
     *
     * @param array        $tag 标签
     * @param string|array $attr
     *
     * @return string
     */
    protected static function getAttr(array $tag, string|array $attr): string
    {
        if (is_string($attr)) {
            $html = empty($tag[$attr]) ? '' : ' ' . $attr . '="' . trim($tag[$attr]) . '"';
        } else {
            $html = '';

            foreach ($attr as $v) {
                $html .= static::getAttr($tag, $v);
            }
        }

        return $html;
    }

    /**
     * 生成TITLE
     *
     * @access protected
     *
     * @param array $tag
     *
     * @return string
     */
    protected static function getTitle(array $tag): string
    {
        $tag['title'] = $tag['title'] ?? $tag['lang'] ?? '';

        return empty($tag['title']) ? '' : ' title="{:\\\wym\\\taglib\\\TagLib::lang("' . trim($tag['title']) . '")}"';
    }

    /**
     * 生成VALUE
     *
     * @access protected
     *
     * @param array $tag
     *
     * @return string
     */
    protected static function getValue(array $tag): string
    {
        $value = $tag['value'] ?? 'rs';

        if (empty($value)) {
            return '';
        }

        $name = empty($tag['name']) ? '' : $tag['name'];

        if (empty($name)) {
            $str = '{present name="' . $value . '"} value="{$' . $value . '}"{/present}';
        } else {
            $str = '{present name="' . $value . '[\'' . $name . '\']"} value="{$' . $value . '[\'' . $name . '\']}"{/present}';
        }

        return in_array($tag['label'], ['text', 'password', 'number', 'hidden']) ? $str : '';
    }

    /**
     * 生成
     *
     *
     * @access protected
     *
     * @param array $tag
     *
     * @return string
     */
    protected static function getType(array $tag): string
    {
        if ($tag['label'] == 'switch') {
            return ' type="checkbox"';
        }

        return empty($tag['label']) ? '' : ' type="' . trim($tag['label']) . '"';
        //        return !in_array($tag['label'], ['text', 'password', 'reset', 'hidden', 'number', 'radio']) ? '' : ' type="' . trim($tag['label']) . '"';
    }

    /**
     * 生成LANG
     *
     * @access protected
     *
     * @param array $tag
     *
     * @return string
     */
    protected static function getLang(array $tag): string
    {
        if ($tag['label'] == 'textarea') {
            $value = $tag['value'] ?? 'rs';
            $name  = empty($tag['name']) ? '' : $tag['name'];

            if (empty($name)) {
                $str = '{present name="' . $value . '"}{$' . $value . '}{/present}';
            } else {
                $str = '{present name="' . $value . '[\'' . $name . '\']"}{$' . $value . '[\'' . $name . '\']}{/present}';
            }
        } else {
            $lang = $tag['lang'] ?? '';
            $lang = empty($lang) && in_array($tag['label'], ['a', 'submit', 'reset']) ? $tag['label'] : $lang;

            if (!strpos($lang, ',')) {
                $lang = "'$lang'";
            }
            $str = '{:\\\wym\\\taglib\\\TagLib::lang(' . $lang . ')}';

            if ($tag['label'] == 'fieldset') {
                $str = $str === '' ? '' : '<legend>' . $str . '</legend>';
            }

            if ($tag['label'] == 'select') {
                $str = $lang == "''" ? '' : '<option value="">{:\\\wym\\\taglib\\\TagLib::lang(' . $lang . ',[\'please select\'])}</option>';
            }

            if ($tag['label'] == 'table') {
                $str = '';
            }
        }

        return $str;
    }

    /**
     * 生成HREF
     *
     * @access protected
     *
     * @param array $tag
     *
     * @return string
     */
    protected static function getHref(array $tag): string
    {
        $href = $tag['href'] ?? '';
        if (!strpos($href, ',')) {
            $href = "'$href'";
        }

        return ' href=' . (empty($tag['href']) ? '"javascript:;"' : '"{:url(' . trim($href) . ')}"');
    }

    /**
     * 生成PLACEHOLDER
     *
     * @access protected
     *
     * @param array $tag
     *
     * @return string
     */
    protected static function getPlaceholder(array $tag): string
    {
        if (isset($tag['lang']) && in_array($tag['label'], ['text', 'password', 'textarea', 'number'])) {
            $tag['lang']  = $tag['placeholder'] ?? '\'' . $tag['lang'] . '\',[\'please enter\']';
            $tag['label'] = '';

            return isset($tag['disabled']) ? '' : ' placeholder="' . static::getLang($tag) . '"';
        }

        return '';
    }

    /**
     * 生成LAY-VERIFY
     *
     * @access protected
     *
     * @param array $tag
     *
     * @return string
     */
    protected static function getLayVerify(array $tag): string
    {
        $str = '';

        if (in_array($tag['label'], ['text', 'password', 'textarea', 'number', 'select', 'radio'])) {
            $str = empty($tag['lay-verify']) ? '' : ' lay-verify="' . trim($tag['lay-verify']) . '"';

            if (isset($tag['lang']) && strpos($str, 'required')) {
                $lang = $tag['lay-reqtext'] ?? '\'cannot be empty\',[\'' . $tag['lang'] . '\']';

                if ($tag['label'] == 'textarea') {
                    $tag['label'] = '';
                }

                if ($tag['label'] == 'select') {
                    $tag['label'] = '';
                    $lang         = $tag['lay-reqtext'] ?? '\'' . $tag['lang'] . '\',[\'please select\']';
                }
                $tag['lang'] = $lang;
                $str         .= ' lay-reqtext="' . static::getLang($tag) . '"';
            }
        }

        return $str;
    }

    /**
     * 生成LAY-SEARCH
     *
     * @access protected
     *
     * @param array $tag
     *
     * @return string
     */
    protected static function getLaySearch(array $tag): string
    {
        return isset($tag['lay-search']) ? (strtolower(
            $tag['lay-search']
        ) == 'cs' ? ' lay-search="cs"' : ' lay-search=""') : '';
    }

    /**
     * 生成AUTOCOMPLETE
     *
     * @access protected
     *
     * @param array $tag
     *
     * @return string
     */
    protected static function getAutocomplete(array $tag): string
    {
        return ' autocomplete="' . (empty($tag['autocomplete']) ? 'off' : $tag['autocomplete']) . '"';
    }

    /**
     * 生成DISABLED
     *
     * @access protected
     *
     * @param array $tag
     *
     * @return string
     */
    protected static function getDisabled(array $tag): string
    {
        return isset($tag['disabled']) ? ' disabled' : '';
    }

    /**
     * 生成URL
     *
     * @access protected
     *
     * @param array  $tag
     * @param string $label
     *
     * @return string
     */
    protected static function getUrl(array $tag, string $label = 'url'): string
    {
        if (empty($tag[$label])) {
            return '';
        }
        $url = $tag[$label];
        if (!strpos($url, ',')) {
            $url = "\"$url\"";
        }

        return ' ' . $label . '="{:url(' . (empty($url) || $url == "\"\"" ? '' : trim($url)) . ')}"';
    }

    public static function load(): string
    {
        // 定义要遍历的目录
        $directory = new DirectoryIterator(dirname(__FILE__) . '/layui');
        $result    = $symbol = '';
        // 遍历目录并打印信息
        foreach ($directory as $fileinfo) {
            if ($fileinfo->isDot()) {
                continue;
            }
            $result .= $symbol . 'wym\taglib\layui\\' . $fileinfo->getBasename('.' . $fileinfo->getExtension());
            $symbol = ',';
        }

        return $result;
    }

    /**
     * 获取语言变量值
     *
     * @param string $name 语言变量名
     * @param array  $vars 动态变量值
     * @param string $lang 语言
     *
     * @return mixed
     */
    static function lang(string $name, array $vars = [], string $lang = ''): mixed
    {
        if (empty($vars)) {
            $vars = [''];
        } else {
            $vars = array_map(function ($v) {
                return self::lang($v);
            }, $vars);
        }

        return lang($name, $vars, $lang);
    }

    /**
     * @param string $name
     * @param string $alias
     * @param array  $result
     *
     * @return array
     */
    private function extracted(string $name, string $alias, array $result): array
    {
        $tag = $this->tags[$name];
        // 设置了标签别名
        if (!empty($alias) && isset($tag['alias'])) {
            $label          = !empty($tag['alias'][1]) ? $tag['alias'][1] : 'label';
            $result[$label] = str_replace($this->tag, '', $alias);
        }

        return $result;
    }
}
